iT邦幫忙

2022 iThome 鐵人賽

DAY 15
1
自我挑戰組

[Dot Net Core](圖解系列與常用套件)系列 第 15

[Dot Net Core] (圖解系列) 15. 委派技巧來保存記憶體內容

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20220915/20144614vziVeUmixy.jpg

無論是什麼架構,當要產生MVC 的Controller時,需要ControllerFactory。在 Dot Net Core中,Host於第一次執行EndpointMiddleware時,會產生ControllerFactory。回顧 ”Http Request to Dot Net Core MVC”中的圖:
https://ithelp.ithome.com.tw/upload/images/20220915/20144614RBwsh7zx7Y.jpg

當S4的步驟,要執行ControllerFactory,此時被呼叫的委派是在Host於第一次執行EndpointMiddleware時產生。而產生的方式是用封閉委派的技巧。

接下來會展示此技巧如何將記憶體保留起來;其實很像javascript的 closure。
首先我們先準備好類別:

public class Provider
{
    private string Info;

    private DateTime Date;

    public Func<string, string> CreateFactory(Descriptor descriptor)
    {

        this.Info = descriptor.Info;
        this.Date = descriptor.Date;


        string CreateMessage(string WantToSay)
        {

            return $" I want to say is {WantToSay} .  More Info is {Info}, on {this.Date.ToString("yyyy-MM-dd")}  ";
        }

        return CreateMessage;

    }

}

Provider 類別中,我們會有 “Info” 與 “Date” 二個欄位,與CreateFactory 函式,將會回傳一個委派函示。然後再準備一個將資料包裝起來的類別” Descriptor”:

public class Descriptor
{

    public string Info;

    public DateTime Date;

    public Descriptor(string strInfo, DateTime date)
    {
        this.Info = strInfo;
        this.Date = date;
    }

}

接下來在 Startup. Configure 函式中做初始化資料(comment: Demo example: initial Data):

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });

        //Demo example: initial Data 
        Descriptor dc = new Descriptor("Generating Description was in Configure Method of  Startup Class !", DateTime.Now);
        Provider provider = new Provider();
        CommonDelegate.DelegateFunc = provider.CreateFactory(dc);

    }

}

從上可以看到在Startup. Configure 函式中,會新增一個Descriptor 的instance,然後利用Provider. CreateFactory將委派函式接收Descriptor的資料後回傳到公用的委派變數。一般來說,離開Startup. Configure後Descriptor 的instance的記憶體會被回收掉,不會存在;而這邊使用一個封閉委派的技巧將Descriptor 的instance的記憶體保留在委派的函式內。

然後到Controller Action的地方去執行此委派函式(comment:Demo example):

public class HomeController : Controller
{
  private readonly ILogger<HomeController> _logger;

  public HomeController(ILogger<HomeController> logger)
  {
      _logger = logger;

  }

  public IActionResult Index()
  {

      //Demo example
      System.Diagnostics.Debug.WriteLine("Example1:");
      System.Diagnostics.Debug.WriteLine(  CommonDelegate.DelegateFunc("Hello Example1 !") );
      System.Diagnostics.Debug.WriteLine("\n");

      return View();
  }
}

會發現執行到此Action時,透過委派函式仍然可以取得到之前在Startup. Configure內所宣告的區域instance “Descriptor”。

實際上執行畫面如下:

https://ithelp.ithome.com.tw/upload/images/20220915/20144614LN7LzGYmyS.jpg

會將” Generating Description was in Configure Method of Startup Class !”字串與日期保存到Descriptor 的instance中,接著離開Startup. Configure去執行Controller Action Method:
https://ithelp.ithome.com.tw/upload/images/20220915/20144614x3RaOSq8RF.jpg

會發現委派函式仍然可以取得Descriptor 的instance中的字串與日期。
這和Javascript 的 Closure 的記憶體保留狀況非常類似。
同樣的效果也可以使用Delegate.CreateDelegate 來達成。

首先準備好類別:

public class Package
{
    private int PackID;
    public Package(int id) 
    { 
        this.PackID = id;
    }

    public void Method1(string Input)
    {
        System.Diagnostics.Debug.WriteLine
             (" Using Delegate.CreateDelegate And Calling Method1 :  PackID = {0}, Input = {1} ", this.PackID, Input);
    }

}


public static class PackageDelegate
{
    public  delegate void PackageDelegateFunc(string Input);
    public  static Delegate DelegateFunc;
}

然後於Startup. Configure做初始化委派:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });

        //E
        Package pk = new Package(DateTime.Now.Millisecond);
        MethodInfo method1 = typeof(Package).GetMethod("Method1", BindingFlags.Public | BindingFlags.Instance);
        PackageDelegate.DelegateFunc = (PackageDelegate.PackageDelegateFunc)Delegate.CreateDelegate(typeof(PackageDelegate.PackageDelegateFunc), pk, method1);  

    }

}

接著於Controller Action中執行:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;

    }

    public IActionResult Index()
    {
        //Example2
        System.Diagnostics.Debug.WriteLine("Example2:");
        PackageDelegate.PackageDelegateFunc pkFunc = (PackageDelegate.PackageDelegateFunc)PackageDelegate.DelegateFunc;
        pkFunc("Hello Example2 !");
        System.Diagnostics.Debug.WriteLine("\n");

        return View();
    }
 }

執行後,當初在Startup. Configure所初始化的內容也可以在委派函式中取得!


上一篇
[Dot Net Core] (圖解系列) 14. List the main Singleton Service during the Host Build
下一篇
[Dot Net Core] (圖解系列) 16. 闡述ControllerFactory形成的方式與時機點
系列文
[Dot Net Core](圖解系列與常用套件)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言